主机迁移

在没有专用服务器的多人网络游戏中,游戏中的其中一位同伴充当游戏权限的中心。这个对等体被称为“主机”。它运行一个服务器和一个“本地客户端”,而其他对等端运行一个“远程客户端”。

如果游戏的主机丢失,那么游戏无法继续。主机可能会丢失,因为玩家离开,主机进程死亡或崩溃,主机的机器被关闭,或因为主机的网络连接丢失。

“主机迁移”功能允许其中一个远程客户端成为新的主机,这样多人游戏就可以继续。

怎么运行的

在启用主机迁移的多人游戏中,同伴的地址将分配给游戏中的同伴。当主机丢失时,一个对等体可以成为新的主机。其他同伴然后连接到新的主机,游戏可以继续。

新的NetworkMigrationManager组件可以放入使用Unity Networking HLAPI的多人游戏中,并且允许游戏在原始主机丢失后继续使用新主机。以下是编辑器检查器中NetworkMigrationManager的屏幕截图。它显示了当前的迁移状态。

NetworkMigrationManager提供了一个简单的用户界面,类似于NetworkManagerHUD。此用户界面用于测试和原型设计;一个真正的游戏将实现一个用于主机迁移的定制用户界面,并且可能定制逻辑 - 可能自动选择新主机而不需要来自用户的输入。

即使迁移可能是由于旧主机失去连接或相当于游戏而发生的,但旧游戏主机有可能作为新主机上的客户端重新加入游戏。

场景中所有联网对象上的SyncVarsSyncLists的状态在主机迁移期间保持不变。这也适用于对象的自定义序列化数据。

当主机丢失时,游戏中的所有玩家对象都被禁用。然后,当其他客户端重新加入新主机上的新游戏时,这些客户端的相应玩家将在主机上重新启用,并在其他客户端上重新生成。所以在主机迁移期间没有玩家状态数据丢失。

注意:只有在客户端可用的数据将在主机迁移期间保留。如果只有服务器上存在数据,则该数据将不可用于成为新主机的客户端。因此,在主机迁移后,主机上未存储在SyncVarsSyncLists中的任何数据都将不可用。

当客户端成为新主机时,将为所有联网对象调用回调函数OnStartServer

在新主机上,NetworkMigrationManager使用函数BecomeNewHost从当前ClientScene中的状态构建联网服务器场景。

启用了主机迁移的游戏中的对等方由其connectionId在服务器上标识。当客户端重新连接到游戏的新主机时,此connectionId将传递到新主机,以便它可以将此客户端与连接到旧主机的客户端相匹配。此Id在ClientScene上设置为“reconnectId”。

非玩家对象

具有客户端权限的非玩家对象也通过主机迁移进行处理。每个客户端所拥有的对象都被禁用,并以与玩家对象相同的方式重新启用。

识别同伴

在主机丢失之前,所有对等点都连接到主机。它们在主机上都有唯一的连接ID - 在主机迁移的上下文中称为“oldConnectionId”。

当选择新主机并且同级重新连接到它时,它们提供它们的“oldConnectionId”以标识它们是哪个对等体。这允许新的主机将这个重新连接的客户端匹配到相应的玩家对象。

旧主机使用零的特殊oldConnectionId重新连接 - 因为它没有与旧主机的连接,所以它是旧主机。有一个常量ClientScene.ReconnectIdHost这个。

使用内置用户界面时,oldConnectionId会自动设置。可以使用NetworkMigrationManager.ResetClientScene.SetReconnectId手动设置。

主机迁移流程

1.MachineA托管启用主机迁移的游戏

2.MachineB启动客户端,并在启用主机迁移的情况下加入游戏
    • MachineB被告知关于同伴(MachineA-0和自身(MachineB)-1)

3.MachineC启动一个客户端并加入启用主机迁移的游戏
    • MachineC被告知关于同伴(MachineA-0,MachineB-1和self(MachineC)-2)

4.MachineA丢失,所以主机丢失

5.MachineB与主机断开连接
    1.MachineB回调函数在客户端上的MigrationManager上调用
    2.所有玩家的MachineB玩家对象都被禁用
    3.MachineB留在在线场景中

6.MachineB使用效用函数来挑选新的主机,挑选自己
    1.MachineB调用BecomeNewHost()
    2.MachineB开始收听
    3.自我的MachineB玩家对象被重新激活
    4.MachineB MachineB的玩家现在回到了游戏中的状态

7.MachineC与主机断开连接
    1.MachineC回调函数在客户端上的MigrationManager上调用
    2.所有玩家的MachineC玩家对象都被禁用
    3.MachineC停留在在线场景中

8.MachineC使用实用程序功能选择新主机,选择MachineB
    • MachineC重新连接到新主机

9.MachineB从MachineC接收连接
    1.MachineC使用oldConnectionId发送重新连接消息(而不是AddPlayer消息)
    2.在服务器上的MigrationManager上调用回调函数
    3.MachineB使用oldConnectionId为该玩家查找禁用的玩家对象,并使用ReconnectPlayerForConnection()重新添加它,
    4.玩家对象为MachineC重新生成
    5.MachineC的玩家现在回到了游戏中的状态

10.MachineA恢复(旧主机)
    1.MachineA使用实用程序功能选择新主机,选择MachineB
    2.MachineA“重新连接”到MachineB

11.MachineB从MachineA接收连接

12.MachineA发送oldConnectionId为零的重新连接消息
    1.在服务器上的MigrationManager(MachineB)上调用回调函数
    2.MachineB使用oldConnectionId为该玩家查找禁用的玩家对象,并使用ReconnectPlayerForConnection()重新添加它,
    3.玩家对象为MachineA重新生成
    4.MachineA的玩家现在重新回到了游戏中的状态

回调函数

NetworkHostMigrationManager上的回调函数

    // called on client after the connection to host is lost. controls whether to switch scenes
    protected virtual void OnClientDisconnectedFromHost(
        NetworkConnection conn, 
        out SceneChangeOption sceneChange)

    // called on host after the host is lost. host MUST change scenes
    protected virtual void OnServerHostShutdown()

    // called on new host (server) when a client from the old host re-connects a player
    protected virtual void OnServerReconnectPlayer(
        NetworkConnection newConnection, 
        GameObject oldPlayer, 
        int oldConnectionId, 
        short playerControllerId)

    // called on new host (server) when a client from the old host re-connects a player
    protected virtual void OnServerReconnectPlayer(
        NetworkConnection newConnection, 
        GameObject oldPlayer, 
        int oldConnectionId, 
        short playerControllerId, 
        NetworkReader extraMessageReader)

    // called on new host (server) when a client from the old host re-connects a non-player object
    protected virtual void OnServerReconnectObject(
        NetworkConnection newConnection, 
        GameObject oldObject, 
        int oldConnectionId)

    // called on both host and client when the set of peers is updated
    protected virtual void OnPeersUpdated(
        PeerListMessage peers)

    // utility function called by the default UI on client after connection to host was lost, to pick a new host.
    public virtual bool FindNewHost(
        out NetworkSystem.PeerInfoMessage newHostInfo, 
        out bool youAreNewHost)

    // called when the authority of a non-player object changes
    protected virtual void OnAuthorityUpdated(
        GameObject go,
        int connectionId,
        bool authorityState)

约束

当主机断开连接时,仅存在于服务器(主机)上的数据将会丢失。为了使游戏能够正确执行主机迁移,必须将重要数据分发给客户端,而不是秘密保存在服务器上。

这适用于直接连接游戏。需要额外的工作才能与媒人和中继服务器一起工作。

🔚